#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "data/gsdata.h"
#include "manager/exportdata.h"
#include "plugins/gsplugin.h"

#include <QApplication>
#include <QFile>
#include <QFileDialog>
#include <QDialogButtonBox>
#include <QMessageBox>
#include <QSignalMapper>
#include <QDesktopWidget>
#include <QTabWidget>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLayout>
#include <QComboBox>
#include <QString>
#include <QStringList>
#include <QCloseEvent>
#include <QScrollArea>
#include <QDesktopServices>
#include <QProcess>

MainWindow::MainWindow(const QList<GSPlugIn*> plugins,
                       QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    setupToolBar();
    setupMenuBar();
    setupWorkSpace();
    setupDockWidget();
    setupPlugIns(plugins);
}

MainWindow::~MainWindow()
{
    delete ui;
    delete dockWorkSpace;
    delete dataManagerWidget;
    delete variablesViewWidget;

    //delete all data.(PS. new gsdata in import dialog)
    for(int i=0; i<dataSet.count(); i++)
        delete dataSet.at(i);
}

void MainWindow::setupToolBar()
{
    ui->actionNew_Plot->setEnabled(false);
    connect(ui->actionFull_Screen, SIGNAL(triggered()),
            this, SLOT(fullScreen()));
    connect(ui->actionExit_FullScreen, SIGNAL(triggered()),
            this, SLOT(exitFullScreen()));
    connect(ui->actionTutorials, SIGNAL(triggered()),
            this, SLOT(openTutorials()));
    connect(ui->action_Export_Data, SIGNAL(triggered()),
            this, SLOT(exportData()));
}

void MainWindow::setupMenuBar()
{ 
    connect(ui->actionAbout_GSPP,SIGNAL(triggered()),
            this, SLOT(aboutGSSP()));
    connect(ui->actionConnections,SIGNAL(triggered()),
            this, SLOT(aboutAuthor()));

    connect(ui->actionNew_WorkSpace, SIGNAL(triggered()),
            this, SLOT(newWorkSpace()));
    connect(ui->actionNew_Plot, SIGNAL(triggered()),
            this, SLOT(newPlot()));

    connect(ui->action_Import_Data, SIGNAL(triggered()),
            this, SLOT(importData()) );

    connect(ui->actionData_Manager, SIGNAL(triggered()),
            this, SLOT(dockWidgetChange()) );
    connect(ui->actionVariables, SIGNAL(triggered()),
            this, SLOT(dockWidgetChange()) );

    connect(ui->actionTileHorizontally, SIGNAL(triggered()),
            this, SLOT(setPlotLayout()) );
    connect(ui->actionTile_Vertically, SIGNAL(triggered()),
            this, SLOT(setPlotLayout()) );

    connect(ui->actionScript_Window, SIGNAL(triggered()),
            this, SLOT(dockWidgetChange()) );
    connect(ui->actionResultLog_Window, SIGNAL(triggered()),
            this, SLOT(dockWidgetChange()) );

}

void MainWindow::setupWorkSpace()
{
    setCentralWidget(ui->verticalLayoutWidget);
    dockWorkSpace = new QTabWidget(this);
    dockWorkSpace->setTabsClosable(true);
    connect(dockWorkSpace, SIGNAL(tabCloseRequested(int)),
            this, SLOT(closeWorkSpace(int)) );
    dockWorkSpace->setTabPosition(QTabWidget::South);
    ui->verticalLayout->addWidget(dockWorkSpace);
    connect(dockWorkSpace, SIGNAL(currentChanged(int)),
            this, SLOT(updateView(int)));
}

void MainWindow::setupDockWidget()
{
    DockOptions opts = AnimatedDocks |  //ForceTabbedDocks
            AllowNestedDocks | AllowTabbedDocks;
    setDockOptions(opts);
    setTabShape(QTabWidget::Rounded);

    variablesViewWidget = new VariablesViewWidget(this);
    addDockWidget(Qt::LeftDockWidgetArea, variablesViewWidget);

    //update view when data updated
    connect(this, SIGNAL(dataUpdated(QList<GSData*>*)),
            variablesViewWidget, SLOT(viewRefresh(QList<GSData*>*)) );
    connect(variablesViewWidget, SIGNAL(deleteVariable(int)),
            this, SLOT(deleteData(int)));
    connect(variablesViewWidget, SIGNAL(duplicateVariable(GSData*)),
            this, SLOT(duplicateVariable(GSData*)));
    connect(variablesViewWidget, SIGNAL(editVariableName(GSData*)),
            this, SLOT(renameVariable(GSData*)));

    dataManagerWidget = new DataManagerWidget(this);
    addDockWidget(Qt::LeftDockWidgetArea, dataManagerWidget);

    //select or add new data view in dataManager Dialog
    connect(variablesViewWidget, SIGNAL(newDataView(GSData*)),
            dataManagerWidget, SLOT(addTabView(GSData*)));

    //delete data view when variable deleted
    connect(this, SIGNAL(deleteDataview(QString)),
            dataManagerWidget, SLOT(deleteTabView(QString)));

    resultLogDialog = new ResultLogDialog(this);
    resultLogDialog->hide();
    connect(resultLogDialog, SIGNAL(rejected()),
            ui->actionResultLog_Window, SLOT(trigger()));
    scriptDialog = new ScriptDialog(this);
    scriptDialog->hide();
    connect(scriptDialog, SIGNAL(rejected()),
            ui->actionScript_Window, SLOT(trigger()));

    connect(ui->actionOnly_Show_Plot, SIGNAL(triggered()),
            this, SLOT(hideAllWindow()));

    //other dialog
    inputDialog = new QInputDialog(this);
}

void MainWindow::setupPlugIns(const QList<GSPlugIn*> plugins)
{
    plugInSet = plugins;

    if(!plugins.isEmpty())
    {
        //Have plugins
        for(int i=0; i<plugins.count(); i++)
        {            
            QString menuName = plugins.at(i)->getMenuName();
            QAction * qmenu;
            switch (plugins.at(i)->getPlugInType()) {
            case GSPlugIn::ANALYSIS_COMPONENT:
                qmenu = ui->menuComponent_Analysis->addAction(menuName);
                break;
            case GSPlugIn::ANALYSIS_CORRELATION:
                qmenu = ui->menuCorrelation_Analysis->addAction(menuName);
                break;
            case GSPlugIn::ANALYSIS_CLUSTER:
                qmenu = ui->menuCluster_Analysis->addAction(menuName);
                break;
            case GSPlugIn::ANALYSIS_EXT:
                qmenu = ui->menu_Analysis->addAction(menuName);
                break;
            case GSPlugIn::PROCESSING_FILTER:
                qmenu = ui->menuFiltering->addAction(menuName);
                break;
            case GSPlugIn::PROCESSING_TRANSFORM:
                qmenu = ui->menuTranforming->addAction(menuName);
                break;
            case GSPlugIn::PROCESSING_RECONSTRUCTION:
                qmenu = ui->menuReconstruction->addAction(menuName);
                break;
            case GSPlugIn::PROCESSING_EXT:
                qmenu = ui->menu_Processing->addAction(menuName);
                break;
            default:
                //default processing applications
                qmenu = ui->menu_Processing->addAction(menuName);
                break;
            }
            menuSet.append(qmenu);
            plugins.at(i)->setData(&dataSet);
            connect(plugins.at(i), SIGNAL(getData(GSData)),
                    this, SLOT(appendData(GSData)));
            connect(qmenu, SIGNAL(triggered()),
                    plugins.at(i), SLOT(create()));                        
        }        
    } 
}

//-------------Begin Data Management-----------------------
void MainWindow::importData()
{
    GSData* inData = new GSData;
    ImportDataDialog dialog(inData, this);
    if (dialog.exec() != QDialog::Accepted)
        return;
    else
    {
        dataSet.append(inData);
        emit dataUpdated(&dataSet);
    }
    dialog.close();
}

void MainWindow::exportData()
{
    ExportData dialog(&dataSet, this);
    dialog.exec();
    dialog.close();
}

void MainWindow::appendData(GSData inData)
{
    if(!isDataDuplicates(inData.name))
    {
        GSData *data = new GSData;
        *data = inData;
        dataSet.append(data);
        emit dataUpdated(&dataSet);
        QMessageBox::warning(this, tr("Information!"),
                           tr("Data has been appended.") );
    }
    else
        QMessageBox::warning(this, tr("Duplicates!"),
                           tr("Please select another Name.") );
}

void MainWindow::deleteData(int index)
{
    GSData *pdata = dataSet.at(index);
    dataSet.removeAt(index);
    emit deleteDataview(pdata->name);
    delete pdata;
    emit dataUpdated(&dataSet);
}

void MainWindow::duplicateVariable(GSData* pdata)
{
    QString newName;
    newName = pdata->name+tr("_copy");
    if(getVaildName(&newName))
    {
        GSData* newData = new GSData;
        *newData = *pdata;
        newData->name = newName;
        dataSet.append(newData);
        emit dataUpdated(&dataSet);
    }
}

void MainWindow::renameVariable(GSData* pdata)
{
    QString newName;
    newName = pdata->name;
    if(getVaildName(&newName))
    {
        emit deleteDataview(pdata->name);
        pdata->name = newName;
        emit dataUpdated(&dataSet);
    }
}

bool MainWindow::getVaildName(QString* newName)
{
    bool ok;
//    inputDialog->exec();
    *newName = inputDialog->getText(
                this, tr("Input New Name"),
                tr("Name:"), QLineEdit::Normal,
                *newName, &ok);
    if(ok)
    {
        *newName = newName->trimmed();
        if (!newName->isEmpty() && newName->isDetached() &&
                newName->isSimpleText())
        {
            if(!isDataDuplicates(*newName))
                return true;
            else
                QMessageBox::warning(this, tr("Duplicates!"),
                                   tr("Please select another Name.") );
        }
        else
        {
            QMessageBox::warning(this, tr("Name Invalid!"),
                               tr("Please input a valid name.") );
        }
    }
    return false;
}

bool MainWindow::isDataDuplicates(QString name)
{
    //check for duplicates
    for(int i=0; i<dataSet.count(); i++)
        if(dataSet.at(i)->name == name)
            return true;
    return false;
}

bool MainWindow::isDataDuplicates(GSData* inData)
{
    //check for duplicates
    for(int i=0; i<dataSet.count(); i++)
        if(dataSet.at(i) == inData)
            return true;
    return false;
}

//-------------End Data Management-----------------------

//-------------Begin Plot Management---------------------
void MainWindow::newPlot()
{
    int idx = dockWorkSpace->currentIndex();
    if(idx != -1)
    {
        WorkSpace* wp = workSpace.at(idx);
        wp->newPlot(&dataSet);
        ui->statusBar->showMessage(
                    tr("Create new plot successful!"));
    }
}

//-------------End Plot Management-----------------------

//----------------Begin Window Property---------------------
void MainWindow::fullScreen()
{
    this->showFullScreen();
    ui->actionFull_Screen->setEnabled(false);
    ui->actionExit_FullScreen->setEnabled(true);
}

void MainWindow::exitFullScreen()
{
    this->showMaximized();
    ui->actionFull_Screen->setEnabled(true);
    ui->actionExit_FullScreen->setEnabled(false);
}

void MainWindow::hideAllWindow()
{
    ui->actionData_Manager->setChecked(false);
    dataManagerWidget->hide();

    ui->actionVariables->setChecked(false);
    variablesViewWidget->hide();

    ui->actionResultLog_Window->setChecked(false);
    resultLogDialog->hide();

    ui->actionScript_Window->setChecked(false);
    scriptDialog->hide();
}

void MainWindow::keyPressEvent(QKeyEvent *e)
{
    switch (e->key() )
    {
        case Qt::Key_F11:
            if(isFullScreen())
            {
                this->showMaximized();
                ui->actionFull_Screen->setEnabled(true);
                ui->actionExit_FullScreen->setEnabled(false);
            }
            else
            {
                this->showFullScreen();
                ui->actionFull_Screen->setEnabled(false);
                ui->actionExit_FullScreen->setEnabled(true);
            }
            break;
        case Qt::Key_Escape:
            this->showMaximized();
            ui->actionFull_Screen->setEnabled(true);
            ui->actionExit_FullScreen->setEnabled(false);
            break;
    }
}

void MainWindow::closeEvent(QCloseEvent *event)
{
    if(event->type() == QEvent::Close)
    {
        QMessageBox::StandardButton button;
        button = QMessageBox::question(this, tr("Questioning?"),
                       QString(tr("Close this project?\n") +
                               tr("Have you saved your data?")),
                       QMessageBox::Yes | QMessageBox::No);
        if (button == QMessageBox::No)
        {
              event->ignore();
          }
        else if (button == QMessageBox::Yes)
        {
            dockWorkSpace->close();
            dataManagerWidget->close();
            variablesViewWidget->close();
            for(int i=0; i<plugInSet.count(); i++)
                plugInSet.at(i)->close();
            event->accept();
          }
    }
}
//------------------End Window Property---------------------

//-------------------Begin WorkSpace------------------------
void MainWindow::newWorkSpace()
{
    bool ok;
    QString name = QInputDialog::getText(
                this,tr("New WorkSpace"),tr("WorkSpace Name："),
                QLineEdit::Normal, tr("WorkSpace 1"), &ok);

    for(int i=0; i<workSpace.count(); i++)
    {
        if(workSpace.at(i)->name == name )
        {
            QMessageBox::warning(
                  this, tr("Duplicates!"),
                  tr("Please Select Another WorkSpace Name.") );
            return;
        }
    }

    if(ok && !name.isEmpty())
    {          
        WorkSpace* wp = new WorkSpace(this);

        wp->name = name;
        workSpace.append(wp);
        QScrollArea* scrollArea = new QScrollArea(this);
        scrollArea->setBackgroundRole(QPalette::Dark);
        scrollArea->setWidget(wp);
        scrollArea->setWidgetResizable(true);
        dockWorkSpace->addTab(scrollArea, name);
        ui->statusBar->showMessage(tr("New File:%1").arg(name));

        int idx = dockWorkSpace->currentIndex();
        updateView(idx);
        ui->actionNew_Plot->setEnabled(true);
    }
}

void MainWindow::closeWorkSpace(int index)
{
    QMessageBox::StandardButton button;
    button = QMessageBox::question(this, tr("Questioning?"),
                   QString(tr("Close this WorkSpace?\n") +
                           tr("Have you saved your data?")),
                   QMessageBox::Yes | QMessageBox::No);
    if (button == QMessageBox::No)
          return;
    else if (button == QMessageBox::Yes)
    {
        dockWorkSpace->removeTab(index);
        WorkSpace* ws = workSpace.at(index);
        workSpace.removeAt(index);
        delete ws;
        if(dockWorkSpace->count()<1)
            ui->actionNew_Plot->setEnabled(false);
      }    
}
//-------------------End WorkSpace------------------------

//-------------------Begin About Property------------------
void MainWindow::openTutorials()
{
    QString path = QApplication::applicationDirPath();
    QString arguments = path + tr("/tools/xpdf/bin/xpdf ") +
            path +tr("/doc/Tutorials.pdf");
    QByteArray ba(arguments.toLocal8Bit());
    system(ba.constData());
}

void MainWindow::aboutGSSP()
{
    QMessageBox::about(this, tr("About GSSP"),
         tr("GSPP - General Signal Processing Platform\n")+
         tr("Version 0.2, 2013/10/10"));
}

void MainWindow::aboutAuthor()
{
    QMessageBox::about(this, tr("Connect Informations"),
                       tr("Author: Kunpeng Wang\n")+
                       tr("Email: wkphnzk@gmail.com"));
}
//-------------------End About Property------------------

//-------------Begin layout Management-------------------
void MainWindow::dockWidgetChange()
{
    if(ui->actionData_Manager->isChecked())
        dataManagerWidget->show();
    else
        dataManagerWidget->hide();

    if(ui->actionVariables->isChecked())
        variablesViewWidget->show();
    else
        variablesViewWidget->hide();   

    if(ui->actionResultLog_Window->isChecked())
        resultLogDialog->show();
    else
        resultLogDialog->hide();

    if(ui->actionScript_Window->isChecked())
        scriptDialog->show();
    else
        scriptDialog->hide();
}

void MainWindow::setPlotLayout()
{
    //find current workspace
    int idx = dockWorkSpace->currentIndex();
    if(idx != -1)
    {
        WorkSpace* wp = workSpace.at(idx);
        wp->layoutChange();
        updateView(idx);
    }
}

void MainWindow::updateView(int idx)
{
    if(idx != -1)
    {
        WorkSpace* wp = workSpace.at(idx);
        if(wp->getLayoutSet() == WorkSpace::VBOX)
        {
            ui->actionTile_Vertically->setEnabled(false);
            ui->actionTileHorizontally->setEnabled(true);
        }
        else
        {
            ui->actionTile_Vertically->setEnabled(true);
            ui->actionTileHorizontally->setEnabled(false);
        }
        wp->updateGeometry();
    }
}
//-------------End layout Management-------------------
